dnd: Fix lifecycle issues with widgets as drag icons
authorMatthias Clasen <mclasen@redhat.com>
Wed, 27 Apr 2016 00:35:25 +0000 (20:35 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Wed, 27 Apr 2016 00:35:25 +0000 (20:35 -0400)
The documentation clearly says that the widget is not destroyed,
but we were in fact failing to keep it alive, since it was still
a child or the icon_window when we destroy that. Fix this by
reparenting the icon_widget out before. Also, deal with the
possibility that the application might destroy the widget
halfway through, for whatever reason.

gtk/gtkdnd.c

index 71913b03d9d8689e1152f32794fc1464c4a7d40f..d0b391c50cca95d32bd83368538d600052f5722a 100644 (file)
@@ -2011,6 +2011,13 @@ gtk_drag_begin (GtkWidget     *widget,
                                   actions, button, event, -1, -1);
 }
 
+static void
+icon_widget_destroyed (GtkWidget         *widget,
+                       GtkDragSourceInfo *info)
+{
+  g_clear_object (&info->icon_widget);
+}
+
 static void
 gtk_drag_set_icon_widget_internal (GdkDragContext *context,
                                    GtkWidget      *widget,
@@ -2041,6 +2048,8 @@ gtk_drag_set_icon_widget_internal (GdkDragContext *context,
   if (!widget)
     goto out;
 
+  g_signal_connect (widget, "destroy", G_CALLBACK (icon_widget_destroyed), info);
+
   gdk_drag_context_set_hotspot (context, hot_x, hot_y);
 
   if (!info->icon_window)
@@ -2715,11 +2724,15 @@ gtk_drag_remove_icon (GtkDragSourceInfo *info)
       widget = info->icon_widget;
       info->icon_widget = NULL;
 
+      g_signal_handlers_disconnect_by_func (widget, icon_widget_destroyed, info);
+
       gtk_widget_hide (widget);
       gtk_widget_set_opacity (widget, 1.0);
 
       if (info->destroy_icon)
         gtk_widget_destroy (widget);
+      else
+        gtk_container_remove (GTK_CONTAINER (info->icon_window), widget);
 
       g_object_unref (widget);
     }